#include "stdafx.h"
#include "Threading.h"

#include <crtdbg.h> 
#include "FirstDx11.h"

 
#include <vector>
#include "d3dx11effect.h"
#include "Input.h"
#include "MyMath.h"
#include <process.h>
#include "loading.h"
#include "..\NBGUI\dx11renderer.h"
#include "..\NBGUI\NBGUI.h"
#pragma comment (lib,"NBGUI.lib")

using namespace FIRSTDX;
using namespace std;
using namespace NBGUI;
using namespace std::tr1;

Dx11Test* g_app;

void addNumCallback( std::vector<info>& i)
{
	addNum(i.front().i);
}


int APIENTRY _tWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR    lpCmdLine,
	int       nCmdShow)
{
	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
	_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );


	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	g_app = new Dx11Test(hInstance,nCmdShow);
	// Main message loop:
	g_app->initialize();
	

	shared_ptr<Dx11Renderer> app( new Dx11Renderer(g_app->getHwnd(),g_app->m_device,g_app->m_context,1440,900) );

	shared_ptr<GuiCore> gui(new GuiCore(app.get()));//TODO , passing the renderer which created by user


	gui->loadLayout("testLayout.xml");
	gui->initDrawing();

	gui->addCallBackFunc(std::string("LoadOne"),std::bind( &addNumCallback, std::placeholders::_1 ));

	calculateCenter(g_app->getHwnd());
	MSG msg;
	while (true)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			gui->processMessage( msg );

			if (msg.message == WM_QUIT)
			{
				break;
			}

			TranslateMessage(&msg);
			DispatchMessage(&msg);

		}else
		{
			g_app->update();
			gui->update();


			g_app->swapBuffer(true);
		}
	}
	int res = (int)msg.wParam;


	delete g_app;
	g_app = nullptr;

	return res;



}




FIRSTDX::Dx11Test::~Dx11Test()
{
	m_ibuff->Release();
	m_vbuff->Release();
	m_vertexVec.clear();
	m_texture->Release();

	if(m_squareVBO)
		m_squareVBO->Release();
	if(m_squareIBO)
		m_squareIBO->Release();
	m_squareVertexVec.clear();
	m_squareIndexVec.clear();

	DeleteCriticalSection(&CriticalSection);
}

void FIRSTDX::Dx11Test::initialize()
{ 
	DXGI_SWAP_CHAIN_DESC des;
	m_swapChain->GetDesc(&des);
	float asp = static_cast<float>(des.BufferDesc.Width)/des.BufferDesc.Height;
	m_camera.setPosition(vec3f(0,0,-40));
	m_camera.setProjection(45.0f,asp,0.1f,1000.0f);

	m_effectVec.push_back( setupShaders( L"shaders.fx") );
	//temp codes:
	m_vertexVec.push_back(vertex(vec3f(-2.0f, -2.0f, 0.0f),vec3f(0,0,1),vec4f(1,0,0,1),vec2f(0,0)));
	m_vertexVec.push_back(vertex(vec3f(2.0f, -2.0f, 0.0f),vec3f(0,0,1),vec4f(0,0,1,1),vec2f(1,0)));
	m_vertexVec.push_back(vertex(vec3f(0.0f, 2.0f, 0.0f),vec3f(0,0,1),vec4f(0,1,0,1),vec2f(0,1)));

	//m_vertexVec.push_back(vertex(vec3f(-1.0f, -1.0f, 2.0f),vec3f(0,0,1),vec4f(1,0,0,0.3f),vec2f(0,0)));
	//m_vertexVec.push_back(vertex(vec3f(1.0f, -1.0f, 2.0f),vec3f(0,0,1),vec4f(1,0,0,0.3f),vec2f(1,0)));
	//m_vertexVec.push_back(vertex(vec3f(0.0f, 1.0f, 2.0f),vec3f(0,0,1),vec4f(1,0,0,0.3f),vec2f(0,1)));

	//origin
	 

	HV(D3DX11CreateShaderResourceViewFromFile(m_device, L"default-alpha.png", NULL, NULL, &m_texture, NULL));
	
	setuoVBO();
	setupIBO();
	
	//for threading
	uintptr_t ptr_t =_beginthread(laoder_enter_point,20480,nullptr);
	// Initialize the critical section one time only.
	if (!InitializeCriticalSectionAndSpinCount(&CriticalSection, 
		0x00000400) ) 
		return;
	
}



void Dx11Test::updateFrame()
{
	if (::GetFocus() == getHwnd())
	{
		InputController::update(m_camera);
	}
	m_context->OMSetDepthStencilState(depthStencilState, 1);

	m_camera.updatePos();
	m_camera.setViewTransformation();
	static float angle = 0;
	angle += 2.0f * PI_OVER_360;
	Matrix4f rotMat = Matrix4f(cos(angle),0,sin(angle),0,
								0,1,0,0,
								-sin(angle),0,cos(angle),0,
								0,0,0,1);

   
	Matrix4f modelMat =  rotMat;
	
	

	ID3DX11EffectTechnique* pRenderTechnique = m_effectVec[0]->GetTechniqueByIndex(0);
	

	HV(m_effectVec[0]->GetVariableByName("modelMat")->AsMatrix()->SetMatrix(modelMat.getDataPointer()));
	HV(m_effectVec[0]->GetVariableByName("viewMat")->AsMatrix()->SetMatrix(m_camera.getViewMatrix().getDataPointer()));
	HV(m_effectVec[0]->GetVariableByName("projMat")->AsMatrix()->SetMatrix(m_camera.getProjection().getDataPointer()));

	HV(pRenderTechnique->GetPassByIndex(0)->Apply(0,m_context));
	m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	//m_effectVec[0]->GetVariableByName("diftex")->AsShaderResource()->SetResource(m_texture);
	uint stride = sizeof(vertex);
	uint offset2= 0;
		m_context->IASetVertexBuffers(0,1,&m_vbuff,&stride,&offset2);
		m_context->IASetInputLayout(m_inputLayout);	
		m_context->IASetIndexBuffer(m_ibuff, DXGI_FORMAT_R32_UINT, 0);
	m_context->DrawIndexed(3,0,0);

	createSquareVI();
	reCreateBuffer();

	for (int i = 0; i< 9; ++i)
	{
		if(IsKeyDown('1' + i) && !InputController::getKeyMap('1'+i) )
		{
			InputController::setKeyMap('1' + i,true);
			addNum(i+1);
		}
	}
	
	//draw other 
	 

 
	rotMat = Matrix4f(1,0,0,0,
					0,1,0,0,
					0,0,1,0,
					0,0,0,1);
	
	HV(m_effectVec[0]->GetVariableByName("modelMat")->AsMatrix()->SetMatrix(rotMat.getDataPointer()));

	

	m_context->IASetVertexBuffers(0,1,&m_squareVBO,&stride,&offset2);
	m_context->IASetIndexBuffer(m_squareIBO, DXGI_FORMAT_R32_UINT, 0);
	
	HV(pRenderTechnique->GetPassByIndex(0)->Apply(0,m_context));
	m_context->DrawIndexed(m_squareIndexVec.size(),0,0);
	 
	
}





void FIRSTDX::Dx11Test::setupIBO()
{
	uint indices[3] = {0,1,2};//test
	D3D11_SUBRESOURCE_DATA srd = { indices, 0, 0 };
	HV(m_device->CreateBuffer(&CD3D11_BUFFER_DESC(sizeof(indices)*sizeof(uint), D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_IMMUTABLE), &srd, &m_ibuff));
	
}

void FIRSTDX::Dx11Test::setuoVBO()
{
	
	D3D11_SUBRESOURCE_DATA srd = { &m_vertexVec[0], 0, 0 };
	HV(m_device->CreateBuffer(&CD3D11_BUFFER_DESC(m_vertexVec.size()*sizeof(vertex), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_IMMUTABLE), &srd, &m_vbuff));
	char* fmt ="PNCT";
	int len = strlen(fmt);
	D3D11_INPUT_ELEMENT_DESC *decl = new D3D11_INPUT_ELEMENT_DESC[len];
	memset(decl, 0, sizeof(D3D11_INPUT_ELEMENT_DESC)*len);
	int offset = 0, semidx = 0;

	for(int i = 0; i<len; i++)
	{
		D3D11_INPUT_ELEMENT_DESC &d = decl[i];
		d.AlignedByteOffset = offset;

		switch(fmt[i])
		{
		case 'P': d.SemanticName = "POSITION"; d.Format = DXGI_FORMAT_R32G32B32_FLOAT; offset += 12; break;
		case 'N': d.SemanticName = "NORMAL";   d.Format = DXGI_FORMAT_R32G32B32_FLOAT; offset += 12; break;
		case 'n': d.SemanticName = "NORMAL";   d.Format = DXGI_FORMAT_R8G8B8A8_UNORM;  offset +=  4; break;
		case 'C': d.SemanticName = "COLOR";    d.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;  offset +=  16; break;
		case 'T': d.SemanticName = "TEXCOORD"; d.Format = DXGI_FORMAT_R32G32_FLOAT;    offset +=  8;d.SemanticIndex = semidx++; break;
		default: assert(0);
		}
	}
	uint stride = sizeof(vertex);
	uint offset2= 0;




	D3DX11_PASS_DESC passDesc;
	ID3DX11EffectTechnique* pRenderTechnique = m_effectVec[0]->GetTechniqueByIndex(0);//or by name
	
	HV(pRenderTechnique->GetPassByIndex(0)->GetDesc(&passDesc));
	HV(m_device->CreateInputLayout(decl,len,passDesc.pIAInputSignature,passDesc.IAInputSignatureSize,&m_inputLayout));

	delete[] decl;
}

void FIRSTDX::Dx11Test::drawOrigin( float len )
{
	m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);

	ID3DX11EffectTechnique* pRenderTechnique = m_effectVec[0]->GetTechniqueByIndex(0);

	HV(pRenderTechnique->GetPassByIndex(1)->Apply(0,m_context));

	m_context->DrawIndexed(6,0,6);
}

void FIRSTDX::Dx11Test::reCreateBuffer()
{
	if (m_squareVBO)
	{
		m_squareVBO->Release();
	}
	if (m_squareIBO)
	{
		m_squareIBO->Release();
	}
	if(m_squareVertexVec.size()==0)
		return;

	D3D11_SUBRESOURCE_DATA srd = { &m_squareVertexVec[0], 0, 0 };
	HV(m_device->CreateBuffer(&CD3D11_BUFFER_DESC(m_squareVertexVec.size()*sizeof(vertex), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_IMMUTABLE), &srd, &m_squareVBO));
	char* fmt ="PNCT";
	int len = strlen(fmt);
	D3D11_INPUT_ELEMENT_DESC *decl = new D3D11_INPUT_ELEMENT_DESC[len];
	memset(decl, 0, sizeof(D3D11_INPUT_ELEMENT_DESC)*len);
	int offset = 0, semidx = 0;

	for(int i = 0; i<len; i++)
	{
		D3D11_INPUT_ELEMENT_DESC &d = decl[i];
		d.AlignedByteOffset = offset;

		switch(fmt[i])
		{
		case 'P': d.SemanticName = "POSITION"; d.Format = DXGI_FORMAT_R32G32B32_FLOAT; offset += 12; break;
		case 'N': d.SemanticName = "NORMAL";   d.Format = DXGI_FORMAT_R32G32B32_FLOAT; offset += 12; break;
		case 'n': d.SemanticName = "NORMAL";   d.Format = DXGI_FORMAT_R8G8B8A8_UNORM;  offset +=  4; break;
		case 'C': d.SemanticName = "COLOR";    d.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;  offset +=  16; break;
		case 'T': d.SemanticName = "TEXCOORD"; d.Format = DXGI_FORMAT_R32G32_FLOAT;    offset +=  8;d.SemanticIndex = semidx++; break;
		default: assert(0);
		}
	}
	uint stride = sizeof(vertex);
	uint offset2= 0;



	delete[] decl;

 
	D3D11_SUBRESOURCE_DATA squareSrd = { &m_squareIndexVec[0], 0, 0 };
	HV(m_device->CreateBuffer(&CD3D11_BUFFER_DESC(m_squareIndexVec.size()*sizeof(uint), D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_IMMUTABLE), &squareSrd, &m_squareIBO));
	

}

void FIRSTDX::Dx11Test::createSquareVI()
{
	m_squareIndexVec.clear();
	m_squareVertexVec.clear();

	float offset = -10.0f;
	for (int i = 0; i< totalCount; ++i)
	{
		//complete
		m_squareIndexVec.push_back(m_squareVertexVec.size());
		m_squareIndexVec.push_back(m_squareVertexVec.size() + 1);
		m_squareIndexVec.push_back(m_squareVertexVec.size() + 2);
		m_squareVertexVec.push_back(vertex(vec3f(offset-1.0f, -1.0f, 1.0f),vec3f(0,0,1),vec4f(0,1,0,1),vec2f(0,0)));
		m_squareVertexVec.push_back(vertex(vec3f(offset+1.0f, -1.0f, 1.0f),vec3f(0,0,1),vec4f(0,1,0,1),vec2f(1,0)));
		m_squareVertexVec.push_back(vertex(vec3f(offset+0.0f, 1.0f, 1.0f),vec3f(0,0,1),vec4f(0,1,0,1),vec2f(0,1)));
		offset+= 1.0f;
	}

	if(currentIdx >= 0)
	{
		//processing
		m_squareIndexVec.push_back(m_squareVertexVec.size());
		m_squareIndexVec.push_back(m_squareVertexVec.size() + 1);
		m_squareIndexVec.push_back(m_squareVertexVec.size() + 2);
		m_squareVertexVec.push_back(vertex(vec3f(offset-1.0f, -1.0f, 1.0f),vec3f(0,0,1),vec4f(1,1,0,1),vec2f(0,0)));
		m_squareVertexVec.push_back(vertex(vec3f(offset+1.0f, -1.0f, 1.0f),vec3f(0,0,1),vec4f(1,1,0,1),vec2f(1,0)));
		m_squareVertexVec.push_back(vertex(vec3f(offset+0.0f, 1.0f, 1.0f),vec3f(0,0,1),vec4f(1,1,0,1),vec2f(0,1)));
		offset += 1.0f;
	}

	for (size_t i = 0; i< toLoadList.size(); ++i)
	{
		//to do
		m_squareIndexVec.push_back(m_squareVertexVec.size());
		m_squareIndexVec.push_back(m_squareVertexVec.size() + 1);
		m_squareIndexVec.push_back(m_squareVertexVec.size() + 2);
		m_squareVertexVec.push_back(vertex(vec3f(offset-1.0f, -1.0f, 1.0f),vec3f(0,0,1),vec4f(1,0,0,1),vec2f(0,0)));
		m_squareVertexVec.push_back(vertex(vec3f(offset+1.0f, -1.0f, 1.0f),vec3f(0,0,1),vec4f(1,0,0,1),vec2f(1,0)));
		m_squareVertexVec.push_back(vertex(vec3f(offset+0.0f, 1.0f, 1.0f),vec3f(0,0,1),vec4f(1,0,0,1),vec2f(0,1)));
		offset += 1.0f;
	}
}

